package com.hisoft.xml;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.apache.log4j.Logger;

import com.hisoft.constant.XMLTestCaseTag;
import com.hisoft.entity.ABaseTag;
import com.hisoft.entity.Assert;
import com.hisoft.entity.Choose;
import com.hisoft.entity.Function;
import com.hisoft.entity.Html;
import com.hisoft.entity.Import;
import com.hisoft.entity.Loop;
import com.hisoft.entity.TestCase;
import com.hisoft.entity.Verify;
import com.hisoft.exception.XpathNotFoundException;
import com.hisoft.type.AssertVerifyType;
import com.hisoft.utility.CommonTool;
import com.hisoft.utility.DataProviderTool;

public class XML2TestCase {
	private static Logger logger = Logger.getLogger(XML2TestCase.class);
	private static XMLInputFactory factory = XMLInputFactory.newInstance();
	private static XMLStreamReader reader;
	private static String fileName;

	/**
	 * 根据file集合，返回相对应的对象，即把xml转化为对象。
	 * <b> </b>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-2
	 */
	public static List<TestCase> xml2TestCaseObject(List<File> files) {
		List<TestCase> list = new ArrayList<TestCase>();
		for (File file : files) {
			list.add(xml2TestCaseObject(file));
		}
		return list;
	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-2
	 */
	private static TestCase xml2TestCaseObject(File file) {
		TestCase tc = null;
		try {
			reader = factory.createXMLStreamReader(new FileReader(file));
			fileName = file.getName();
			tc = new TestCase();
			tc.setFileName(fileName);
			while (reader.hasNext()) {
				switch (reader.getEventType()) {
				case XMLStreamReader.START_ELEMENT:
					String name = reader.getLocalName();
					if (name.equals(XMLTestCaseTag.HTML)) {
						tc.addOperate(xml2Html());
					} else if (name.equals(XMLTestCaseTag.FUNCTION)) {
						tc.addOperate(xml2Function());
					} else if (name.equals(XMLTestCaseTag.IMPORTXML)) {
						tc.addOperate(xml2Import());
					} else if (name.equals(XMLTestCaseTag.VERIFY)) {
						tc.addOperate(xml2Verify());
					} else if (name.equals(XMLTestCaseTag.ASSERT)) {
						tc.addOperate(xml2Assert());
					} else if (name.equals(XMLTestCaseTag.CHOOSE)) {
						tc.addOperate(xml2Choose());
					} else if (name.equals(XMLTestCaseTag.LOOP)) {
						tc.addOperate(xml2Loop());
					} else if (name.equals(XMLTestCaseTag.TEST_CASE_NAME)) {
						tc.setTestCaseName(reader.getElementText());
					} else if (name.equals(XMLTestCaseTag.TEST_CASE_VERSION)) {
						tc.setTestCaseVersion(reader.getElementText());
					} else if (name.equals(XMLTestCaseTag.DESCRIPTION)) {
						tc.setDescription(reader.getElementText());
					} else if (name.equals(XMLTestCaseTag.CREATED)) {
						tc.setCreatedAuthor(reader.getAttributeValue(null, XMLTestCaseTag.AUTHOR));
						tc.setCreatedDate(reader.getAttributeValue(null, XMLTestCaseTag.DATE));
					} else if (name.equals(XMLTestCaseTag.LAST_UPDATED)) {
						tc.setLastUpdatedAuthor(reader.getAttributeValue(null, XMLTestCaseTag.AUTHOR));
						tc.setLastUpdatedDate(reader.getAttributeValue(null, XMLTestCaseTag.DATE));
					} else if (name.equals(XMLTestCaseTag.RECORDINFO)) {
						tc.setRecordInfoAccount(reader.getAttributeValue(null, XMLTestCaseTag.ACCOUNT));
						tc.setRecordInfoIndex(reader.getAttributeValue(null, XMLTestCaseTag.DEVICE_INDEX));
					} else if (name.equals(XMLTestCaseTag.TEST)) {
						// TODO
					} else if (name.equals(XMLTestCaseTag.TESTCASE)) {
						// TODO
					} else if (name.equals(XMLTestCaseTag.ANNOTATION)) {
						// TODO
					} else {
						logger.debug("xml2TestCaseObject unhandle tag: " + name);
					}
					break;
				case XMLStreamReader.END_ELEMENT:
					break;
				default:
					break;
				}
				if (reader.hasNext()) {
					reader.next();
				}// 获取下一个解析事件
			}
		} catch (FileNotFoundException e) {
			logger.error(e.getMessage(), e);
		} catch (XMLStreamException e) {
			logger.error(e.getMessage(), e);
		}
		return tc;
	}

	private static ABaseTag xml2Loop() throws XMLStreamException {
		Loop loop = new Loop();
		loop.setTime(reader.getAttributeValue(null, XMLTestCaseTag.TIMES));
		loop.setLineNumb(reader.getLocation().getLineNumber());
		List<ABaseTag> loopDos = new ArrayList<ABaseTag>();
		Boolean flag = true;
		while (reader.hasNext() && flag) {
			switch (reader.getEventType()) {
			case XMLStreamReader.START_ELEMENT:
				String name = reader.getLocalName();
				if (name.equals(XMLTestCaseTag.HTML)) {
					loopDos.add(xml2Html());
				} else if (name.equals(XMLTestCaseTag.VERIFY)) {
					loopDos.add(xml2Verify());
				} else if (name.equals(XMLTestCaseTag.ASSERT)) {
					loopDos.add(xml2Assert());
				} else if (name.equals(XMLTestCaseTag.FUNCTION)) {
					loopDos.add(xml2Function());
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				if (reader.getLocalName().equals(XMLTestCaseTag.LOOP)) {
					flag = false;
				}
				break;
			}
			reader.next();// 获取下一个解析事件
		}
		int tempTimes = CommonTool.String2Int(loop.getTime());
		List<ABaseTag> tempLoopDos = new ArrayList<ABaseTag>();
		for (int i = 0; i < tempTimes; i++) {
			for (ABaseTag a : loopDos) {
				if (a.clone() != null) {
					tempLoopDos.add(a.clone());
				}
			}
		}
		loop.setLoop(tempLoopDos);
		return loop;
	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @throws XMLStreamException
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-2
	 */
	private static Html xml2Html() throws XMLStreamException {
		Html html = new Html();
		html.setCommand(reader.getAttributeValue(null, XMLTestCaseTag.COMMAND));

		try {
			html.setTarget(DataProviderTool.getData(reader.getAttributeValue(null, XMLTestCaseTag.TARGET)));
			html.setValue(DataProviderTool.getData(reader.getAttributeValue(null, XMLTestCaseTag.VALUE)));
		} catch (XpathNotFoundException e) {
			logger.error("file: " + fileName + " line: " + reader.getLocation().getLineNumber() + " " + e.getMessage(), e);
		}
		html.setLineNumb(reader.getLocation().getLineNumber());
		while (reader.getEventType() != XMLStreamReader.END_ELEMENT) {
			if (reader.getEventType() == XMLStreamConstants.CHARACTERS) {
				if (reader.isWhiteSpace()) {
					html.setInfo("");
				} else {
					html.setInfo(reader.getText());
				}
				break;
			} else if (reader.hasNext()) {
				reader.next();
			}
		}
		return html;
	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @throws XMLStreamException
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-3
	 */
	private static Function xml2Function() throws XMLStreamException {
		Function function = new Function();
		function.setCommand(reader.getAttributeValue(null, XMLTestCaseTag.COMMAND));
		try {
			function.setTarget(DataProviderTool.getData(reader.getAttributeValue(null, XMLTestCaseTag.TARGET)));
			function.setValue(DataProviderTool.getData(reader.getAttributeValue(null, XMLTestCaseTag.VALUE)));
		} catch (XpathNotFoundException e) {
			logger.error("file: " + fileName + " line: " + reader.getLocation().getLineNumber() + " " + e.getMessage(), e);
		}
		function.setLineNumb(reader.getLocation().getLineNumber());
		while (reader.getEventType() != XMLStreamReader.END_ELEMENT) {
			if (reader.getEventType() == XMLStreamConstants.CHARACTERS) {
				if (reader.isWhiteSpace()) {
					function.setInfo("");
				} else {
					function.setInfo(reader.getText());
				}
				break;
			} else if (reader.hasNext()) {
				reader.next();
			}
		}
		return function;
	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-17
	 */
	private static AssertVerifyType getAVT(String str) {
		AssertVerifyType avt = AssertVerifyType.EQUALS;
		if (CommonTool.isEmpty(str)) {
		} else {
			try {
				avt = AssertVerifyType.valueOf(str.toUpperCase());
			} catch (IllegalArgumentException e) {
				logger.error(e.getMessage() + " change to default");
				avt = AssertVerifyType.EQUALS;
			}
		}
		return avt;
	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @throws XMLStreamException
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-2
	 */
	private static Verify xml2Verify() throws XMLStreamException {
		Verify verify = new Verify();
		try {
			verify.setExcepted(DataProviderTool.getData(reader.getAttributeValue(null, XMLTestCaseTag.EXPECTED)));
		} catch (XpathNotFoundException e) {
			logger.error("file: " + fileName + " line: " + reader.getLocation().getLineNumber() + " " + e.getMessage(), e);
		}
		verify.setAvt(getAVT(reader.getAttributeValue(null, XMLTestCaseTag.TYPE)));
		Boolean flag = true;
		while (reader.hasNext() && flag) {
			switch (reader.getEventType()) {
			case XMLStreamReader.START_ELEMENT:
				verify.setLineNumb(reader.getLocation().getLineNumber());
				String name = reader.getLocalName();
				if (name.equals(XMLTestCaseTag.HTML)) {
					verify.setVerify(xml2Html());
				} else if (name.equals(XMLTestCaseTag.FUNCTION)) {
					verify.setVerify(xml2Function());
				} else if (name.equals(XMLTestCaseTag.VERIFY)) {
				} else {
					logger.debug("xml2Verify unhandle tag: " + name);
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				if (reader.getLocalName().equals(XMLTestCaseTag.VERIFY)) {
					flag = false;
				}
				break;
			default:
				break;
			}
			if (reader.hasNext()) {
				reader.next();
			}// 获取下一个解析事件
		}
		verify.setInfo(verify.getVerify().getInfo());
		return verify;
	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @throws XMLStreamException
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-2
	 */
	private static Assert xml2Assert() throws XMLStreamException {
		Assert assert1 = new Assert();
		try {
			assert1.setExcepted(DataProviderTool.getData(reader.getAttributeValue(null, XMLTestCaseTag.EXPECTED)));
		} catch (XpathNotFoundException e) {
			logger.error("file: " + fileName + " line: " + reader.getLocation().getLineNumber() + " " + e.getMessage(), e);
		}
		assert1.setAvt(getAVT(reader.getAttributeValue(null, XMLTestCaseTag.TYPE)));
		Boolean flag = true;
		while (reader.hasNext() && flag) {
			switch (reader.getEventType()) {
			case XMLStreamReader.START_ELEMENT:
				assert1.setLineNumb(reader.getLocation().getLineNumber());
				String name = reader.getLocalName();
				if (name.equals(XMLTestCaseTag.HTML)) {
					assert1.setVerify(xml2Html());
				} else if (name.equals(XMLTestCaseTag.FUNCTION)) {
					assert1.setVerify(xml2Function());
				} else if (name.equals(XMLTestCaseTag.ASSERT)) {
				} else {
					logger.debug("xml2Assert unhandle tag: " + name);
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				if (reader.getLocalName().equals(XMLTestCaseTag.ASSERT)) {
					flag = false;
				}
				break;
			default:
				break;
			}
			if (reader.hasNext()) {
				reader.next();
			}// 获取下一个解析事件
		}
		assert1.setInfo(assert1.getVerify().getInfo());
		return assert1;
	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-2
	 */
	private static Choose xml2Choose() throws XMLStreamException {
		Choose choose = new Choose();
		choose.setLineNumb(reader.getLocation().getLineNumber());
		Boolean flag = true;
		while (reader.hasNext() && flag) {
			switch (reader.getEventType()) {
			case XMLStreamReader.START_ELEMENT:
				String name = reader.getLocalName();
				if (name.equals(XMLTestCaseTag.WHEN)) {
					choose.setWhen(xml2When());
				} else if (name.equals(XMLTestCaseTag.DO)) {
					choose.setDo(xml2Do());
				} else if (name.equals(XMLTestCaseTag.OTHERWISE)) {
					choose.setOtherwise(xml2Otherwise());
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				if (reader.getLocalName().equals(XMLTestCaseTag.CHOOSE)) {
					flag = false;
				}
				break;
			}
			if (reader.hasNext()) {
				reader.next();
			}// 获取下一个解析事件
		}
		return choose;

	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-2
	 */
	private static ABaseTag xml2When() throws XMLStreamException {
		ABaseTag i = null;
		Boolean flag = true;
		while (reader.hasNext() && flag) {
			switch (reader.getEventType()) {
			case XMLStreamReader.START_ELEMENT:
				String name = reader.getLocalName();
				if (name.equals(XMLTestCaseTag.VERIFY)) {
					i = xml2Verify();
					flag = false;
				} else if (name.equals(XMLTestCaseTag.ASSERT)) {
					i = xml2Assert();
					flag = false;
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				if (reader.getLocalName().equals(XMLTestCaseTag.WHEN)) {
					flag = false;
				}
				break;
			}
			reader.next();// 获取下一个解析事件
		}
		return i;
	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-2
	 */
	private static List<ABaseTag> xml2Do() throws XMLStreamException {
		List<ABaseTag> chooseDos = new ArrayList<ABaseTag>();
		Boolean flag = true;
		while (reader.hasNext() && flag) {
			switch (reader.getEventType()) {
			case XMLStreamReader.START_ELEMENT:
				String name = reader.getLocalName();
				if (name.equals(XMLTestCaseTag.HTML)) {
					chooseDos.add(xml2Html());
				} else if (name.equals(XMLTestCaseTag.VERIFY)) {
					chooseDos.add(xml2Verify());
				} else if (name.equals(XMLTestCaseTag.ASSERT)) {
					chooseDos.add(xml2Assert());
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				if (reader.getLocalName().equals(XMLTestCaseTag.DO)) {
					flag = false;
				}
				break;
			}
			reader.next();// 获取下一个解析事件
		}
		return chooseDos;
	}

	/**
	 * 
	 * <b> </b>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-6-2
	 */
	private static List<ABaseTag> xml2Otherwise() throws XMLStreamException {
		List<ABaseTag> otherWise = new ArrayList<ABaseTag>();
		Boolean flag = true;
		while (reader.hasNext() && flag) {
			switch (reader.getEventType()) {
			case XMLStreamReader.START_ELEMENT:
				String name = reader.getLocalName();
				if (name.equals(XMLTestCaseTag.HTML)) {
					otherWise.add(xml2Html());
				} else if (name.equals(XMLTestCaseTag.VERIFY)) {
					otherWise.add(xml2Verify());
				} else if (name.equals(XMLTestCaseTag.ASSERT)) {
					otherWise.add(xml2Assert());
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				if (reader.getLocalName().equals(XMLTestCaseTag.OTHERWISE)) {
					flag = false;
				}
				break;
			}
			reader.next();// 获取下一个解析事件
		}
		return otherWise;
	}

	private static Import xml2Import() throws XMLStreamException {
		Import import_ = new Import();
		import_.setLineNumb(reader.getLocation().getLineNumber());
		import_.setScr(reader.getAttributeValue(null, XMLTestCaseTag.SRC));
		import_.setImportXML(XML2Import.xml2Import(import_.getScr()));
		return import_;
	}

}
